﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;

namespace SimpleTaskManager.Domain.Entities
{
    /// <summary>
    /// The class to represent a task
    /// </summary>
    public class Task
    {
        /// <summary>
        /// ID field
        /// </summary>
        public int TaskID { get; set; }

        /// <summary>
        /// The name of the task
        /// </summary>
        [Display(Name="Name")]
        [Required(ErrorMessage = "Please enter a name")]
        public string Name { get; set; }

        /// <summary>
        /// The ID of the task's leader
        /// </summary>
        [Display(Name = "Leader")]
        public int? LeaderId { get; set; }

        /// <summary>
        /// The leader of the task
        /// </summary>
        [ForeignKey("LeaderId")]
        public virtual User Leader { get; set; }

        /// <summary>
        /// A number between 0 and 1 representing the progress percentage of the task
        /// </summary>
        [NotMapped]
        public decimal? Progress
        {
            get
            {
                //If it doesn't have any subtasks then count the progress based on the status
                if (SubTasks.Count == 0)
                {
                    switch (Status)
                    {
                        case TaskStatusEnum.Failed: return null;
                        case TaskStatusEnum.Finished: return 1; //100%
                        case TaskStatusEnum.InProgress: 
                            //If it's in progress, then calculate the progress as the proportion of
                            // the days passed since creation 
                            int daysGone = (new TimeSpan(DateTime.Now.Ticks - StartDate.Ticks)).Days;
                            // and the number of days from the creation until the deadline
                            int allDays = (new TimeSpan(EndDate.Ticks - StartDate.Ticks)).Days;
                            return ((decimal)daysGone / allDays);
                        case TaskStatusEnum.New: return 0;
                        case TaskStatusEnum.Pending: return 0;
                        case TaskStatusEnum.Rejected: return null;
                        default: return null;
                    }
                }

                // If it has subtasks, then the progress will be
                // the sum of the progress of the tasks
                decimal sum = SubTasks.Sum(t => t.Progress ?? 0);
                // divided by the total number of tasks
                return sum / SubTasks.Count;
            }
        }

        /// <summary>
        /// The collection which represents the people in the task
        /// </summary>
        public virtual ICollection<User> Group { get; set; }

        /// <summary>
        /// Represents the required number of people.
        /// Aka, the max size of the group that can be associated with the task
        /// </summary>
        [Display(Name="No. of people needed")]
        [Required(ErrorMessage="You have to specify the number of people required for this task")]
        public int GroupSize { get; set; }

        /// <summary>
        /// The collection of the subtasks
        /// </summary>
        [InverseProperty("ParentTask")]
        public virtual ICollection<Task> SubTasks { get; set; }

        /// <summary>
        /// A reference to the parent task
        /// <remarks>If the task doesn't have a parent, then it is a project's main task.</remarks>
        /// </summary>
        public virtual Task ParentTask { get; set; }

        /// <summary>
        /// The collection of tasks which have to be completed to start this task
        /// </summary>
        public virtual ICollection<Task> Requirements { get; set; }

        /// <summary>
        /// The collection of tasks which requires this task to be complemented before they can be started
        /// </summary>
        public virtual ICollection<Task> RequiredBy { get; set; }

        /// <summary>
        /// The creation date of the task
        /// </summary>
        [DataType(DataType.Date)]
        [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
        public DateTime StartDate { get; set; }

        /// <summary>
        /// The backing field for the deadline
        /// </summary>
        private DateTime _endDate = DateTime.Now;

        /// <summary>
        /// The deadline of the task
        /// </summary>
        [Display(Name="Deadline")]
        [DataType(DataType.Date)]
        [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
        public DateTime EndDate { get { return _endDate; } set { _endDate = value; } }

        /// <summary>
        /// The backing field for the status enumeration
        /// </summary>
        public int StatusRep
        {
            get { return (int)Status; }
            set { Status = (TaskStatusEnum)value; }
        }

        /// <summary>
        /// Represents the status of the project.
        /// </summary>
        public TaskStatusEnum Status { get; set; }

        /// <summary>
        /// The rating of the task.
        /// </summary>
        public int Rating { get; set; }

        /// <summary>
        /// A description of the task
        /// </summary>
        [Display(Name = "Description")]
        public string Description { get; set; }

        /// <summary>
        /// A collection of the entered working hours
        /// </summary>
        public virtual ICollection<WorkingHoursEntry> WorkingHoursEntries { get; set; }

        /// <summary>
        /// A collection of the uploaded reports
        /// </summary>
        [InverseProperty("Task")]
        public virtual ICollection<ReportHeader> Reports { get; set; }

        /// <summary>
        /// Sets the leader to null and changes the task state, to show that it is without leader
        /// </summary>
        public void RemoveLeader()
        {
            Leader = null;

            Status = TaskStatusEnum.LeaderNeeded;
        }
    }
}